# -*- coding:utf-8 -*-
import copy
import json
import re
import logging
import json
from log import logger

pattern = re.compile(r'\d+')


class BaseCmd(object):
    """Class for base cmd functionality"""
    def __init__(self, client):
        self.stdout = None
        self.stderr = None
        self.client = client

    def execute_cmd(self, cmd):
        logger.debug('执行命令：%s' % cmd)
        _, stdout, stderr = self.client.exec_command(cmd)
        stderr = [out.strip() for out in stderr if out]
        if stderr:
            logger.debug('执行 %s 错误：%s' % (cmd, '\n'.join(stderr)))
        stdout = [out.strip() for out in stdout if out]
        stdout = '\n'.join(stdout)
        if 'Exit Code' in stdout and 'Exit Code: 0x00' not in stdout:
            raise '执行code异常'
        return stdout


class Mvcli(BaseCmd):
    """Class for config BOSS card from mvcli functionality"""

    BASE_CMD = "/code/pxe_agent/tools/MegaRAID/mvcli/cli/mvcli"

    # 判断是否有BOSS卡
    def has_adp(self):
        adp_cmd = [self.BASE_CMD, 'info -o hba']
        adp_res = self.execute_cmd(' '.join(adp_cmd))
        adp_id = []
        for i in adp_res.split("\n"):
            if '\r' in i or 'Exit Code' in i or '' == i:
                continue
            if 'No adapter is found.' in i:
                return -1

            if 'Adapter ID:' in i:
                adp_id.append(i.split(':')[1].strip())
        return adp_id

    # 设置当前操作的BOSS卡
    def set_adp(self, adp_num):
        adp_cmd = [self.BASE_CMD, 'adapter  -i %s' % adp_num]
        adp_res = self.execute_cmd(' '.join(adp_cmd))
        logger.debug('Current adapter is %s' % adp_num)

    # 获取disk 数量
    def get_disk_num(self):
        disk_num_cmd = [self.BASE_CMD, "info -o pd | grep 'Total # of PD'"]
        disk_num_res = self.execute_cmd(' '.join(disk_num_cmd))
        disk_num = pattern.findall(disk_num_res)[-1]
        return disk_num

    # 获取disk id
    def get_disk_id(self):
        disk_id_cmd = [self.BASE_CMD, "info -o pd | grep 'PD ID' | awk '{print$3}'"]
        disk_id_res = self.execute_cmd(' '.join(disk_id_cmd))
        id_list = []
        for i in disk_id_res.split("\n"):
            if '\r' in i or 'Exit Code' in i or '' == i:
                continue
            id_list.append(i.strip())
        return id_list

    # 获取disk info
    def get_disk_info(self, pd_id):
        disk_info_cmd = [self.BASE_CMD, 'info -o pd -i %s' % pd_id]
        disk_info_res = self.execute_cmd(' '.join(disk_info_cmd))
        disk_info = {}
        disk_info_format = {}
        for i in disk_info_res.split("\n"):
            if '\r' in i or 'Exit Code' in i or '' == i or ':' not in i:
                continue
            param = i.split(':')
            disk_info.update({param[0].strip(): param[1].strip()})
        disk_info_format.update({'slot_number': disk_info['PD ID']})
        if 'K' in disk_info['Size']:
            disk_info_format.update(
                {'size': str(int(float(disk_info['Size'].split("K")[0].strip()) / 1024 / 1024)) + "GB"})
        elif 'M' in disk_info['Size']:
            disk_info_format.update({'size': str(int(float(disk_info['Size'].split("M")[0].strip()) / 1024)) + "GB"})
        disk_info_format.update({'media_type': disk_info['SSD Type']})
        disk_info_format.update({'pd_type': disk_info['Type'].split(' ')[0].strip()})
        disk_info_format.update({'raw_data': json.dumps(disk_info)})
        disk_info_format.update({'model': disk_info['model']})
        return disk_info_format

    # 创建raid
    def create_raid(self, raid_type, pd_id, name):
        create_cmd = [self.BASE_CMD, 'create -o vd -r%s -d %s -n %s' % (raid_type, pd_id, name)]
        create_res = self.execute_cmd(' '.join(create_cmd))
        logger.debug('BOSS adapter create raid%s success' % raid_type)
        logger.debug(create_res)

    # 删除raid
    def del_raid(self, vd_id):
        del_cmd = [self.BASE_CMD, 'delete -o vd -i %s <<EOF\ny\nEOF' % vd_id]
        del_res = self.execute_cmd(' '.join(del_cmd))
        logger.debug('BOSS adapter delete raid %s success' % vd_id)
        logger.debug(del_res)

    # 获取所有raid信息
    def get_vd_info(self):
        get_vd_count_cmd = [self.BASE_CMD, 'info -o vd']
        get_vd_count_res = self.execute_cmd(' '.join(get_vd_count_cmd))
        vd_all_info = {}
        for i in get_vd_count_res.split("\n"):
            if '\r' in i or 'Exit Code' in i or '' == i or ':' not in i:
                continue
            if 'No virtual disk is found.' in get_vd_count_res:
                return -1

            param = i.split(':')
            vd_all_info.update({param[0].strip(): param[1].strip()})
        return vd_all_info

    # 获取vd id
    def get_vd_id(self):
        vd_id_cmd = [self.BASE_CMD, "info -o vd | grep 'id:' | awk '{print$2}'"]
        vd_id_res = self.execute_cmd(' '.join(vd_id_cmd))
        id_list = []
        for i in vd_id_res.split("\n"):
            if '\r' in i or 'Exit Code' in i or '' == i:
                continue
            id_list.append(i.strip())
        return id_list

    # 获取raid info
    def get_raid(self, vd_id):
        get_cmd = [self.BASE_CMD, 'info -o vd -i %s' % vd_id]
        get_res = self.execute_cmd(' '.join(get_cmd))
        vd_info = {}
        for i in get_res.split("\n"):
            if '\r' in i or 'Exit Code' in i or '' == i or ':' not in i:
                continue
            param = i.split(':')
            vd_info.update({param[0].strip(): param[1].strip()})
        if 'K' in vd_info['size']:
            vd_info['size'] = str(int(float(vd_info['size'].split("K")[0].strip()) / 1024 / 1024)) + "GB"
        elif 'M' in vd_info['size']:
            vd_info['size'] = str(int(float(vd_info['size'].split("M")[0].strip()) / 1024)) + "GB"
        return vd_info


class Megacli(BaseCmd):
    BASE_CMD = "/code/pxe_agent/tools/MegaRAID/MegaCli/MegaCli64"

    # 获取adapter数
    def get_adp_info(self):
        try:
            adp_count_cmd = [self.BASE_CMD, '-adpcount', '| grep', "'Controller Count'"]
            get_adp_count = self.execute_cmd(' '.join(adp_count_cmd))
            adp_num = pattern.findall(get_adp_count)[0]
            logger.debug("处理结果：adp_num是： %s" % adp_num)
        except:
            adp_num = StorcliX86(self.client).get_adp_info()
        return adp_num

    # 获取enclosure id
    def get_adp_enclosure(self, adp_num):
        try:
            adp_enclosure_cmd = [self.BASE_CMD, '-pdlist', '-a%s' % adp_num, '| grep', "'Enclosure Device'"]
            enclosure_infos = self.execute_cmd(' '.join(adp_enclosure_cmd))
            enclosure_info = enclosure_infos.split('\n')[0]
            enclosure_id = pattern.findall(enclosure_info)[0]
            logger.debug("处理结果：enclosure_id是： %s" % enclosure_id)
            if not enclosure_id:
                raise 'megacli查询enclosure id结果为空'
        except Exception as e:
            enclosure_id = StorcliX86(self.client).get_adp_enclosure(0)
        return enclosure_id

    # 获取获取raid卡下的磁盘数
    def get_adp_disk_num(self, adp_num):
        adp_enclosure_disk_cmd = [self.BASE_CMD, '-PdGetNum',
                                  "-a%s | sed 's/Number of Physical Drives on Adapter /Adapter/g'" % adp_num]
        enclosure_disk_infos = self.execute_cmd(' '.join(adp_enclosure_disk_cmd))
        pd_count_dict = {}
        for i in enclosure_disk_infos.split("\n"):
            if '\r' in i or 'Exit Code' in i or '' == i:
                continue
            ld_params = i.split(':')
            pd_count_dict.update({ld_params[0].strip(): ld_params[1].strip()})
        return pd_count_dict

    # 获取disk详情
    def get_pd_info(self, enclosure, slot, adp_num):
        pd_info_dict = {}
        pd_one_info = {}
        pd_info_cmd = [self.BASE_CMD, '-pdinfo', '-PhysDrv', '[%s:%s]' % (enclosure, slot), '-a%s' % adp_num]
        pd_info = self.execute_cmd(' '.join(pd_info_cmd))
        for i in pd_info.split("\n"):
            if '\r' in i or 'Exit Code' in i or '' == i:
                continue
            pd_params = i.split(':')
            pd_info_dict.update({pd_params[0].strip(): pd_params[1].strip()})
        pd_one_info.update({"slot_number": pd_info_dict["Slot Number"]})
        pd_info_dict["Raw Size"] = pd_info_dict["Raw Size"].split('[')[0].replace(" ", "")
        if 'TB' in pd_info_dict["Raw Size"]:
            pd_info_dict["Raw Size"] = str(int(float(pd_info_dict["Raw Size"].split("TB")[0]) * 1024)) + "GB"
        elif "GB" in pd_info_dict["Raw Size"]:
            pd_info_dict["Raw Size"] = str(int(float(pd_info_dict["Raw Size"].split("GB")[0]))) + "GB"
        pd_one_info.update({"size": pd_info_dict["Raw Size"]})
        pd_one_info.update({"media_type": pd_info_dict["Media Type"]})
        pd_one_info.update({"pd_type": pd_info_dict["PD Type"]})
        pd_one_info.update({"firmware_state": pd_info_dict["Firmware state"]})
        pd_one_info.update({"foreign_state": pd_info_dict["Foreign State"]})
        logger.debug("physical device information: %s" % pd_one_info)
        pd_one_info.update({"raw_data": json.dumps(pd_info_dict)})
        return pd_one_info

    def get_pd_brief_info(self, enclosure, slot, adp_num):
        pd_info_dict = {}
        pd_one_info = {}
        pd_info_cmd = [self.BASE_CMD, '-pdinfo', '-PhysDrv', '[%s:%s]' % (enclosure, slot), '-a%s' % adp_num]
        pd_info = self.execute_cmd(' '.join(pd_info_cmd))
        for i in pd_info.split("\n"):
            if '\r' in i or 'Exit Code' in i or '' == i:
                continue
            pd_params = i.split(':')
            pd_info_dict.update({pd_params[0].strip(): pd_params[1].strip()})
        pd_one_info.update({"disk_model": re.sub(' +', ' ', pd_info_dict["Inquiry Data"])})
        pd_info_dict["Raw Size"] = pd_info_dict.get("Raw Size").split('[')[0].replace(" ", "")
        if 'TB' in pd_info_dict.get("Raw Size"):
            pd_info_dict["Raw Size"] = str(int(float(pd_info_dict.get("Raw Size").split("TB")[0]) * 1024)) + "G"
        elif "GB" in pd_info_dict.get("Raw Size"):
            pd_info_dict["Raw Size"] = str(int(float(pd_info_dict.get("Raw Size").split("GB")[0]))) + "G"
        pd_one_info.update({"disk_capacity": pd_info_dict.get("Raw Size")})
        pd_one_info.update({"disk_media": pd_info_dict.get("Media Type")})
        logger.info(
            f"physical device enclosure {enclosure} slot {slot} adapter {adp_num} brief information: {pd_one_info}")
        return pd_one_info

    # 获取disk数量
    def get_pd_count(self, adp_num):
        pd_count_cmd = [self.BASE_CMD, '-PDGetNum', '-a%s' % adp_num, '| grep', "'Number of Physical'"]
        pd_count = self.execute_cmd(' '.join(pd_count_cmd))
        pd_num = pattern.findall(pd_count)[-1]
        logger.debug("Adapter %s has %s physical device(slot)" % (adp_num, pd_num))
        return pd_num

    # 获取slot number
    def get_slot_num(self, adp_num):
        try:
            slot_num_cmd = [self.BASE_CMD, '-PDList', '-a%s' % adp_num, '| grep', "'Slot Number'", "| awk '{print$3}'"]
            slot_num_res = self.execute_cmd(' '.join(slot_num_cmd))
            slot_list = []
            for i in slot_num_res.split("\n"):
                if '\r' in i or 'Exit Code' in i or '' == i:
                    continue
                slot_list.append(i.strip())
            logger.debug("处理结果：slot_list是： %s" % slot_list)
            if not slot_list:
                raise 'megacli查询slot number为空'
        except:
            slot_list = StorcliX86(self.client).get_adp_slot(adp_num)
        return slot_list

    # 获取raid Target Id 和Name
    def get_ld_brief_info(self, adp_num):
        try:
            ld_brief_info_cmd = [self.BASE_CMD, '-LdPdInfo', '-a%s' % adp_num, '| grep -E', "'Virtual Drive:|Name'",
                                 '| sed', "'s/Virtual Drive:/split flag Virtual Drive:/g'"]
            ld_brief_info_res = self.execute_cmd(' '.join(ld_brief_info_cmd))
            ld_brief_info = []
            for i in ld_brief_info_res.split('split flag '):
                if '\r' in i or 'Exit Code' in i or '' == i:
                    continue
                ld_one_brief = {}
                for j in i.split('\n'):
                    if '\r' in j or 'Exit Code' in j or '' == j:
                        continue
                    brief_info_params = j.split(':')
                    if brief_info_params[0].strip() == 'Virtual Drive':
                        ld_one_brief.update(
                            {brief_info_params[0].strip(): brief_info_params[1].strip().split('(')[0].strip()})
                        ld_one_brief.update(
                            {brief_info_params[1].strip().split('(')[1]: brief_info_params[2].strip().split(')')[0]})
                    else:
                        ld_one_brief.update({brief_info_params[0].strip(): brief_info_params[1].strip()})
                ld_brief_info.append(ld_one_brief)
                logger.debug(ld_one_brief)
            logger.debug("处理结果：ld_brief_info是： %s" % ld_brief_info)
            return ld_brief_info
        except:
            return StorcliX86(self.client).get_vd_info(adp_num)

    # 获取Target ID 和 Size
    def get_ld_size_info(self, adp_num):
        ld_size_info_cmd = [self.BASE_CMD, '-LdPdInfo', '-a%s' % adp_num, '| grep -E', "'Virtual Drive:|Size'",
                            '| sed', "'s/Virtual Drive:/split flag Virtual Drive:/g'"]
        ld_size_info_res = self.execute_cmd(' '.join(ld_size_info_cmd))
        ld_size_info = []
        for i in ld_size_info_res.split('split flag '):
            if '\r' in i or 'Exit Code' in i or '' == i:
                continue
            ld_one_size = {}
            for j in i.split('\n'):
                if '\r' in j or 'Exit Code' in j or '' == j:
                    continue
                size_info_params = j.split(':')
                if size_info_params[0].strip() == 'Virtual Drive':
                    # {'Virtual Drive': '239', 'Size': ''}
                    # 添加Virtual Drive 的key-value
                    ld_one_size.update(
                        {size_info_params[0].strip(): size_info_params[1].strip().split('(')[0].strip()})
                elif size_info_params[0].strip() == 'Size':
                    ld_one_size.update({size_info_params[0].strip(): size_info_params[1].strip()})
            ld_size_info.append(ld_one_size)
            logger.debug(ld_one_size)
        return ld_size_info

    # 获取raid 详情
    def get_ld_info(self, target_id, adp_num):
        ld_info_cmd = [self.BASE_CMD, '-LdInfo', '-L%s' % target_id, '-a%s' % adp_num]
        ld_info_res = self.execute_cmd(' '.join(ld_info_cmd))
        ld_info_dict = {}
        for i in ld_info_res.split("\n"):
            if '\r' in i or 'Exit Code' in i or '' == i:
                continue
            pd_params = i.split(':')
            if pd_params[0].strip() == "Size":
                pd_params[1] = pd_params[1].replace(" ", "")
                if 'TB' in pd_params[1]:
                    pd_params[1] = str(int(float(pd_params[1].split("TB")[0]) * 1024)) + "GB"
                elif 'GB' in pd_params[1]:
                    pd_params[1] = str(int(float(pd_params[1].split("GB")[0]))) + "GB"
            ld_info_dict.update({pd_params[0].strip(): pd_params[1].strip()})
        return ld_info_dict

    # 获取raid数
    def get_ld_count(self, adp_num):
        try:
            ld_count_cmd = [self.BASE_CMD, '-LdGetNum',
                            "-a%s | sed 's/Number of Virtual Drives Configured on Adapter /Adapter/g'" % adp_num]
            ld_count_res = self.execute_cmd(' '.join(ld_count_cmd))
            ld_count_dict = {}
            for i in ld_count_res.split("\n"):
                if '\r' in i or 'Exit Code' in i or '' == i:
                    continue
                ld_params = i.split(':')
                ld_count_dict.update({ld_params[0].strip(): ld_params[1].strip()})
            logger.debug("处理结果：ld_count_dict是： %s" % ld_count_dict)
        except:
            ld_count_dict = StorcliX86(self.client).get_ld_count(0)
        return ld_count_dict

    # 删除raid
    def del_ld(self, target_id, adp_num):
        try:
            del_ld_cmd = [self.BASE_CMD, '-CfgLdDel', '-L%s' % target_id, '-a%s' % adp_num]
            del_ld_res = self.execute_cmd(' '.join(del_ld_cmd))
            logger.debug("处理结果：del_ld_res是： %s" % del_ld_res)
        except:
            del_ld_res = StorcliX86(self.client).del_ld(target_id, adp_num)
        return del_ld_res

    # 删除raid (配置全清)
    def del_all(self, adp_num):
        try:
            del_all_cmd = [self.BASE_CMD, '-CfgClr', '-a%s' % adp_num]
            del_all_res = self.execute_cmd(' '.join(del_all_cmd))
            logger.debug("处理结果：del_all_res是： %s" % del_all_res)
        except:
            del_all_res = StorcliX86(self.client).del_raid(adp_num)
        return del_all_res

    # 设置raid名称
    def set_raid_name(self, raid_name, target_id, adp_num):
        raid_name = raid_name.replace(" ", "")
        set_raid_name_cmd = [self.BASE_CMD, '-LDSetProp', '-Name', "%s" % raid_name, '-L%s' % target_id,
                             '-a%s' % adp_num]
        raid_name_res = self.execute_cmd(' '.join(set_raid_name_cmd))
        logger.debug(raid_name_res)

    # 设置disk状态
    def set_pd_state(self, enclosure, slot, adp_num):
        pd_state_cmd = [self.BASE_CMD, '-PDMakeGood', '-PhysDrv', '[%s:%s]' % (enclosure, slot), '-a%s' % adp_num]
        pd_state_res = self.execute_cmd(' '.join(pd_state_cmd))
        logger.debug(pd_state_res)

    # 扫描外来配置的个数
    def scan_foreign(self, adp_num):
        scan_foreign_cmd = [self.BASE_CMD, '-cfgforeign -scan -a%s' % adp_num]
        scan_foreign_res = self.execute_cmd(' '.join(scan_foreign_cmd))
        for i in scan_foreign_res.split("\n"):
            if '\r' in i or 'Exit Code' in i or '' == i:
                continue
            if 'There is no foreign configuration on controller' in i:
                return 0
            else:
                return pattern.findall(i)[0]

    # 导入外来配置
    def import_foreign(self):
        import_foreign_cmd = [self.BASE_CMD, '-CfgForeign -Import -aall']
        import_foreign_res = self.execute_cmd(' '.join(import_foreign_cmd))
        logger.debug(import_foreign_res)

    # 清除外来配置
    def clear_foreign(self):
        clear_foreign_cmd = [self.BASE_CMD, '-CfgForeign -clear -aall']
        clear_foreign_res = self.execute_cmd(' '.join(clear_foreign_cmd))
        logger.debug(clear_foreign_res)

    # 设置JBOD模式
    def set_jbod(self, adp_num):
        try:
            set_jbod_cmd = [self.BASE_CMD, '-AdpSetProp -EnableJBOD -1 -a%s' % adp_num]
            set_jbod_res = self.execute_cmd(' '.join(set_jbod_cmd))
            logger.debug("处理结果：set_jbod_res是： %s" % set_jbod_res)
        except:
            set_jbod_res = StorcliX86(self.client).set_jbod(adp_num)
        return set_jbod_res

    # 清除jbod模式
    def del_jbod(self):
        del_jbod_res = ''
        try:
            del_jbod_cmd = [self.BASE_CMD, '-AdpSetProp -EnableJBOD -0 -aALL']
            del_jbod_res = self.execute_cmd(' '.join(del_jbod_cmd))
            logger.debug("处理结果：del_jbod_res是： %s" % del_jbod_res)
        except:
            del_jbod_res += StorcliX86(self.client).del_jbod(0)
        return del_jbod_res

    # 设置单个磁盘JBOD
    def set_disk_jbod(self, adp_num, enclosure, slot):
        set_disk_jbod_res = ''
        try:
            set_disk_jbod_cmd = [self.BASE_CMD, '-PDMakeJBOD -PhysDrv[%s:%s] -a%s' % (enclosure, slot, adp_num)]
            set_disk_jbod_res = self.execute_cmd(' '.join(set_disk_jbod_cmd))
            logger.debug("处理结果：set_disk_jbod_res是： %s" % set_disk_jbod_res)
        except:
            set_disk_jbod_res += StorcliX86(self.client).set_disk_jbod(adp_num, enclosure, slot)
        return set_disk_jbod_res

    # 清除单个磁盘JBOD
    def del_disk_jbod(self, adp_num, enclosure, slot):
        del_disk_jbod_res = ''
        try:
            del_disk_jbod_cmd = [self.BASE_CMD, '-PDMakeGood -PhysDrv[%s:%s] -Force -a%s' % (enclosure, slot, adp_num)]
            del_disk_jbod_res = self.execute_cmd(' '.join(del_disk_jbod_cmd))
            logger.debug("处理结果：del_disk_jbod_res是： %s" % del_disk_jbod_res)
        except:
            del_disk_jbod_res += StorcliX86(self.client).del_disk_jbod(adp_num, enclosure, slot)
        return del_disk_jbod_res

    # 创建raid
    def create_raid(self, raid_type, enclosure_slot, adp_num):
        create_res = ''
        try:
            create_cmd = [self.BASE_CMD, '-CfgLdAdd', '-r%s[%s]' % (raid_type, enclosure_slot), 'WB', 'RA', 'Direct',
                          '-a%s' % adp_num]
            create_res = self.execute_cmd(' '.join(create_cmd))
            logger.debug("处理结果：create_res是： %s" % create_res)
            target_id = None
            for i in create_res.split("\n"):
                if '\r' in i or 'Exit Code' in i or '' == i:
                    continue
                if 'Created VD' in i:
                    target_id = pattern.findall(i)[-1]
                    break
            return create_res
        except:
            create_res += StorcliX86(self.client).create_raid(raid_type, enclosure_slot, adp_num)
        return create_res


class Storcli(BaseCmd):
    BASE_CMD = "/code/pxe_agent/tools/MegaRAID/storcli/storcli64"

    # 获取adapter数
    def get_adp_info(self):
        adp_count_cmd = [self.BASE_CMD, 'show all', '| grep', "'Number of Controllers = '"]
        get_adp_count = self.execute_cmd(' '.join(adp_count_cmd))
        adp_num = pattern.findall(get_adp_count)[0]
        logger.debug("处理结果：adp_num是： %s" % adp_num)
        return adp_num

    # 获取enclosure id
    def get_adp_enclosure(self, adp_num):
        adp_enclosure_cmd = [self.BASE_CMD, '/c%s' % adp_num, 'show |awk',
                             "'/EID:Slt DID State DG/,/EID=Enclosure Device ID\|Slt=Slot No/ {if ($0 !~ /EID:Slt|EID=Enclosure/) print}' | awk NF |grep -v '^-' |awk {'print $1'}"]
        # 252:0
        # 252:1
        enclosure_infos = self.execute_cmd(' '.join(adp_enclosure_cmd))
        enclosure_info = enclosure_infos.split('\n')[0]
        enclosure_id = enclosure_info.split(":")[0]
        logger.debug("处理结果：enclosure_id是： %s" % enclosure_id)
        return enclosure_id

    # 获取slot id
    def get_adp_slot(self, adp_num):
        adp_slot_cmd = [self.BASE_CMD, '/c%s' % adp_num, 'show |awk',
                             "'/EID:Slt DID State DG/,/EID=Enclosure Device ID\|Slt=Slot No/ {if ($0 !~ /EID:Slt|EID=Enclosure/) print}' | awk NF |grep -v '^-' |awk {'print $1'}"]
        # 252:0
        # 252:1
        slot_infos = self.execute_cmd(' '.join(adp_slot_cmd))
        slot_info = slot_infos.split('\n')
        slot_list = []
        for info in slot_info:
            slot_id = info.split(":")
            slot_list.append(slot_id[1])
        logger.debug("处理结果：slot_list是： %s" % set(slot_list))
        return list(set(slot_list))

    # 获取获取raid卡下的磁盘数
    def get_adp_disk_num(self, adp_num):
        # Physical Drives = 2
        adp_enclosure_disk_cmd = [self.BASE_CMD, "/c%s" % adp_num, "show", "|grep 'Physical Drives = '"]
        enclosure_disk_infos = self.execute_cmd(' '.join(adp_enclosure_disk_cmd))
        for i in enclosure_disk_infos.split("\n"):
            if '\r' in i or 'Exit Code' in i or '' == i:
                continue
            ld_params = i.split('Physical Drives = ')
            return ld_params[1].strip()

    def get_info(self, adp_num):
        info_cmd = [self.BASE_CMD, "/c%s" % adp_num, "show", "J"]
        info_res = self.execute_cmd(' '.join(info_cmd))
        logger.debug("处理结果：info_res是： %s" % info_res)
        return info_res

    # 获取vd--target_id信息
    def get_vd_info(self, adp_num):
        # 以json的形式输出
        vd_info_cmd = [self.BASE_CMD, "/c%s" % adp_num, "show", "J"]
        vd_info_res = self.execute_cmd(' '.join(vd_info_cmd))
        vd_ids = []
        try:
            vd_info_res = json.loads(vd_info_res)
            vd_list = vd_info_res.get('Controllers')[0].get('Response Data').get('VD LIST')
            if vd_list:
                # 0/239
                # [{'Target Id': 239}]
                vd_ids = [{'Target Id': vd_id.get('DG/VD').split('/')[1]} for vd_id in vd_list]
        except Exception as e:
            logger.debug('get_vd_info error: %s' % e)
        logger.debug("处理结果：vd_ids是： %s" % vd_ids)
        return vd_ids

    # 获取raid数
    def get_ld_count(self, adp_num):
        ld_count_cmd = [self.BASE_CMD, '/c%s' % adp_num, "show", "| grep 'Virtual Drives' | awk {'print $4'}"]
        ld_count_res = self.execute_cmd(' '.join(ld_count_cmd))
        ld_count_dict = {}
        for i in ld_count_res.split("\n"):
            if '\r' in i or 'Exit Code' in i or '' == i:
                continue
            ld_count_dict.update({adp_num: i})
        logger.debug("处理结果：ld_count_dict是： %s" % ld_count_dict)
        return ld_count_dict

    # 获取disk详情
    def get_pd_info(self, enclosure, slot, adp_num):
        pd_one_info = {}
        pd_info_cmd = [self.BASE_CMD, '/c%s/e%s/s%s' % (adp_num, enclosure, slot), 'show |awk',
                       "'/EID:Slt DID State DG/,/EID=Enclosure Device ID\|Slt=Slot No/ {if ($0 !~ /EID:Slt|EID=Enclosure/) print}' | awk NF |grep -v '^-'"]
        # 252:0     1 Onln   0 446.625 GB SATA SSD N   N  512B HWE62ST3480L003N U  -
        pd_info = self.execute_cmd(' '.join(pd_info_cmd))
        pd_infos = pd_info.split(" ")
        pd_infos = [i for i in pd_infos if i != " "]
        logger.debug("pd_infos is : %s" % pd_infos)
        pd_one_info.update({"slot_number": slot})
        # 因pd_infos元素长度有时不一致
        Gb_size_index, Tb_size_index, size_index = None, None, None
        try:
            if 'GB' in pd_infos:
                Gb_size_index = pd_infos.index('GB')
                size_index = Gb_size_index
            elif 'TB' in pd_infos:
                Tb_size_index = pd_infos.index('TB')
                size_index = Tb_size_index
        except Exception as e:
            logger.debug('index error: %s ' % str(e))
        if Gb_size_index:
            pd_size = str(int(float(pd_infos[Gb_size_index - 1]))) + 'GB'
        elif Tb_size_index:
            pd_size = str(int(float(pd_infos[Tb_size_index - 1]) * 1024)) + 'GB'
        else:
            pd_size = '0GB'
        pd_one_info.update({"size": pd_size})
        pd_one_info.update({"media_type": pd_infos[size_index + 2]})
        pd_one_info.update({"pd_type": pd_infos[size_index + 1]})
        pd_one_info.update({"firmware_state": ""})
        pd_one_info.update({"foreign_state": ""})
        logger.debug("physical device information: %s" % pd_one_info)
        pd_one_info.update({"raw_data": str(pd_infos)})
        return pd_one_info

    # 获取磁盘内存信息
    def get_pd_brief_info(self, enclosure, slot, adp_num):
        pd_one_info = {}
        pd_info_cmd = [self.BASE_CMD, '/c%s/e%s/s%s' % (adp_num, enclosure, slot), 'show |awk',
                       "'/EID:Slt DID State DG/,/EID=Enclosure Device ID\|Slt=Slot No/ {if ($0 !~ /EID:Slt|EID=Enclosure/) print}' | awk NF |grep -v '^-'"]
        # 252:0     1 Onln   0 446.625 GB SATA SSD N   N  512B HWE62ST3480L003N U  -
        pd_info = self.execute_cmd(' '.join(pd_info_cmd))
        pd_infos = pd_info.split(" ")
        pd_infos = [i for i in pd_infos if i != " "]
        logger.debug("pd_infos is : %s" % pd_infos)
        pd_one_info.update({"slot_number": slot})
        # 因pd_infos元素长度有时不一致
        Gb_size_index, Tb_size_index, size_index = None, None, None
        try:
            if 'GB' in pd_infos:
                Gb_size_index = pd_infos.index('GB')
                size_index = Gb_size_index
            elif 'TB' in pd_infos:
                Tb_size_index = pd_infos.index('TB')
                size_index = Tb_size_index
        except Exception as e:
            logger.debug('index error: %s ' % str(e))
        if Gb_size_index:
            pd_size = str(int(float(pd_infos[Gb_size_index - 1]))) + 'G'
        elif Tb_size_index:
            pd_size = str(int(float(pd_infos[Tb_size_index - 1]) * 1024)) + 'G'
        else:
            pd_size = '0G'
        pd_one_info.update({"disk_capacity": pd_size})
        pd_one_info.update({'disk_media': pd_infos[size_index + 2]})
        pd_one_info.update({'disk_model': pd_infos[20]})
        return pd_one_info

    # 创建raid
    def create_raid(self, raid_type, enclosure_slot, adp_num):
        create_cmd = [self.BASE_CMD, '/c%s' % adp_num, 'add vd type=raid%s' % raid_type, 'drives=%s' % enclosure_slot]
        create_res = self.execute_cmd(' '.join(create_cmd))
        logger.debug("处理结果：create_res是： %s" % create_res)
        return create_res

    # 删除raid（单清）
    def del_ld(self, target_id, adp_num):
        del_ld_cmd = [self.BASE_CMD, '/c%s/v%s' % (adp_num, target_id), 'delete force']
        del_ld_res = self.execute_cmd(' '.join(del_ld_cmd))
        logger.debug("处理结果：del_ld_res是： %s" % del_ld_res)
        return del_ld_res

    # 删除raid
    def del_raid(self, adp_num):
        del_cmd = [self.BASE_CMD, '/c%s' % adp_num, "delete config"]
        del_res = self.execute_cmd(' '.join(del_cmd))
        logger.debug("处理结果：del_all_res是： %s" % del_res)
        return del_res

    # 设置JBOD模式
    def set_jbod(self, adp_num):
        set_jbod_cmd = [self.BASE_CMD, '/c%s' % adp_num, 'set jbod=on']
        set_jbod_res = self.execute_cmd(' '.join(set_jbod_cmd))
        logger.debug("处理结果：set_jbod_res是： %s" % set_jbod_res)
        return set_jbod_res

    # 清除jbod模式
    def del_jbod(self, adp_num):
        del_jbod_cmd = [self.BASE_CMD, '/c%s' % adp_num, 'set jbod=off']
        del_jbod_res = self.execute_cmd(' '.join(del_jbod_cmd))
        logger.debug("处理结果：del_jbod_res是： %s" % del_jbod_res)
        return del_jbod_res

    # 设置单个磁盘JBOD
    def set_disk_jbod(self, adp_num, enclosure, slot):
        set_disk_jbod_cmd = [self.BASE_CMD, '/c%s/e%s/s%s' % (adp_num, enclosure, slot), 'set JBOD force']
        set_disk_jbod_res = self.execute_cmd(' '.join(set_disk_jbod_cmd))
        logger.debug("处理结果：set_disk_jbod_res是： %s" % set_disk_jbod_res)
        return set_disk_jbod_res

    # 清除单个磁盘JBOD
    def del_disk_jbod(self, adp_num, enclosure, slot):
        del_disk_jbod_cmd = [self.BASE_CMD, '/c%s/e%s/s%s' % (enclosure, slot, adp_num), 'set good']
        del_disk_jbod_res = self.execute_cmd(' '.join(del_disk_jbod_cmd))
        logger.debug("处理结果：del_disk_jbod_res是： %s" % del_disk_jbod_res)
        return del_disk_jbod_res


class StorcliX86(Storcli):
    BASE_CMD = "/code/pxe_agent/tools/MegaRAID/storcli_x86/storcli64"


class SaSCli(BaseCmd):
    BASE_CMD = "/code/pxe_agent/tools/SAS3IRCU_P16/sas3ircu_linux_x86_rel/sas3ircu"

    # 获取adapter数
    def get_adp_info(self):
        """
        Avago Technologies SAS3 IR Configuration Utility.
Version 17.00.00.00 (2018.04.02)
Copyright (c) 2009-2018 Avago Technologies. All rights reserved.


         Adapter      Vendor  Device                       SubSys  SubSys
 Index    Type          ID      ID    Pci Address          Ven ID  Dev ID
 -----  ------------  ------  ------  -----------------    ------  ------
   0     SAS3008       1000h   97h    00h:56h:00h:00h      1000h   3090h
SAS3IRCU: Utility Completed Successfully.
        """
        adp_count_cmd = [self.BASE_CMD, 'list', '| wc -l']
        get_adp_count = self.execute_cmd(' '.join(adp_count_cmd))
        # 减去无效的9行
        adp_num = int(get_adp_count) - 9
        logger.debug("This service has %s Adapter(raid card)" % adp_num)
        return adp_num

    # 获取enclosure id
    def get_adp_enclosure(self, adp_num):
        adp_enclosure_cmd = [self.BASE_CMD, adp_num, "display", "|grep 'Enclosure #                             :'"]
        enclosure_infos = self.execute_cmd(' '.join(adp_enclosure_cmd))
        enclosure_id = pattern.findall(enclosure_infos)[0]
        logger.debug("Adapter %s enclosure id is %s" % (adp_num, enclosure_id))
        return enclosure_id

    # 获取获取raid卡下的磁盘数
    def get_adp_disk_num(self, adp_num):
        adp_enclosure_disk_cmd = [self.BASE_CMD, adp_num, "display",
                                  "|grep 'Enclosure #                             :'"]
        enclosure_disk_infos = self.execute_cmd(' '.join(adp_enclosure_disk_cmd))
        enclosure_ids = pattern.findall(enclosure_disk_infos)
        pd_count_dict = {}
        if enclosure_ids:
            pd_count_dict = {"Adapter" + str(adp_num): len(enclosure_ids)}
        return pd_count_dict

    # 获取slot number
    def get_slot_num(self, adp_num):
        slot_num_cmd = [self.BASE_CMD, adp_num, "display", "|grep 'Slot #                             :'"]
        slot_num_res = self.execute_cmd(' '.join(slot_num_cmd))
        slot_list = pattern.findall(slot_num_res)
        return slot_list

    # 创建raid
    def create_raid(self, raid_type, enclosure_slot, adp_num):
        create_cmd = [self.BASE_CMD, str(adp_num), "create RAID%s" % raid_type, "MAX %s" % enclosure_slot, "noprompt"]
        create_res = self.execute_cmd(' '.join(create_cmd))
        logger.debug(create_res)

    # 删除raid
    def del_raid(self, vd_id):
        del_cmd = [self.BASE_CMD, str(vd_id), "delete noprompt"]
        del_res = self.execute_cmd(' '.join(del_cmd))
        logger.debug('BOSS adapter delete raid %s success' % vd_id)
        logger.debug(del_res)
